const Koa = require('koa')
// 创建koa 实例的
const app = new Koa()

const views = require('koa-views')
const json = require('koa-json')
const onerror = require('koa-onerror')
const bodyparser = require('koa-bodyparser')
const logger = require('koa-logger')
// session redis 相关
const session = require('koa-generic-session')
// koa操作redis 的包
const redisStore = require('koa-redis')
// 引入路由相关
// view 路由
const errorRoute = require('./routes/view/error')
const userViewRoute = require('./routes/view/user')

// api 路由
const userRoute = require('./routes/api/user')


// 引入常量密匙 ， 这个密匙是给token用的
const { SECRET: secret } = require('../conf/constants') 
const { SESSION_SECRET_KEY } = require('./conf/secretKeys')
// 配置验证登录验证中间件
// const jwtKoa = require('koa-jwt')

// 自定义处理验证失败
// app.use(function(ctx, next){
//   return next().catch((err) => {
//     if (401 === err.status) {
//       ctx.status = 200
//       ctx.body = {
//         errno: -1,
//         data: '',
//         message: 'token失效，请重新登录'
//       }
//     } else {
//       throw err
//     }
//   })
// })

// 验证jwt 中间件， 这里会拦截看你是否携带了token ， 会验证你的
// app.use(jwtKoa({
//   secret
// }).unless({
//   // \ 是转义符
//   path: [/^\/users\/login/], // 定义要忽略的路径
// }))

// 引入配置
const { REDIS_CONF: { host: redisHost, port: redisPort } } = require('./conf/db')
// 引入配置项
const { isPro } = require('./util/env')

const index = require('./routes/index')
const users = require('./routes/users')
// const xx = require('./util/env')
// console.log(xx)

// 配置sesion
// session的密码
app.keys = [SESSION_SECRET_KEY]
// 配置session 相关的东西
app.use(session({
  key: 'weibo.sid', // 浏览器cookie的名字
  prefix: 'weibo.sess', // redis key 的前缀
  cookie: {
    path: '/', // 生效路径
    httpOnly: true, // 设置客户端只读的权限
    maxAge: 24 * 60 * 60 * 1000 // 有效时长， 单位是毫秒
  },
  store: redisStore({ // redis 上的存储
    all: `${redisHost}:${redisPort}`
  })
}))

// 配置jwt 的信息


// 服务器错误配置项目
let onerrorConf = {}

// 线上才开始错误处理
if(isPro){
  onerrorConf = { 
    redirect: '/error', // 重定向 到error  
  }
}
// error handler, 出现错误的情况中间件儿， 服务器出现异常时 ，第二个参数可以传入对应的处理
onerror(app,onerrorConf)

// middlewares
// bodyparser 参数处理中间件， json， form  text
app.use(bodyparser({
  enableTypes:['json', 'form', 'text']
}))
// 解析json的？
app.use(json())
// 日志中间件
app.use(logger())
// 静态资源中间件
app.use(require('koa-static')(__dirname + '/public'))

// 静态路由
app.use(views(__dirname + '/views', {
  extension: 'ejs'
}))

// logger
// 日志输出 , 上面有，我们就先注释掉这个了
// app.use(async (ctx, next) => {
//   const start = new Date()
//   await next()
//   const ms = new Date() - start
//   console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
// })

// routes
// 路由中间件， 这里调用需要携带.routes , 后面的allowedMethods 是干啥的
//allowedMethods 是返回如果请求方式不对会返回405的
// app.use(index.routes(), index.allowedMethods())
app.use(index.routes())
app.use(users.routes(), users.allowedMethods())

app.use(userRoute.routes(), userRoute.allowedMethods())
app.use(userViewRoute.routes(), userViewRoute.allowedMethods())
// 错误页有* 所以要放在最后
app.use(errorRoute.routes(), errorRoute.allowedMethods())

// error-handling
// 对应的错误处理回调，服务器错误事件
//
app.on('error', (err, ctx) => {
  console.error('server error', err, ctx)
})

module.exports = app
